
#ifndef RTHTTPPROXYINFOGETTER_H
#define RTHTTPPROXYINFOGETTER_H

#include "RtReferenceControl.h"
#include "RtHttpInterface.h"
#include "RtHttpUtilClasses.h"
#include "RtHttpProxySetting.h"
#include "RtTimerWrapper.h"
#include "RtObserver.h"
#include "RtChannelFile.h"
#include <vector>

class IRtChannelHttpClient;

class /*RT_API_EXPORT*/ IRtHttpProxyInfoGetter : public IRtReferenceControl
{
public:
	// called once when initing proxy setting
	virtual RtResult StartUp(const CRtString &aData) = 0;

	// move to the first proxy info
	virtual BOOL Reset(const CRtString &aHost, WORD aPort) = 0;

	typedef enum { NEXT_SUCCESS, NEXT_FAILED, NEXT_WOULDBLCOK } NextReturn;

	virtual NextReturn GetNextProxyInfo(
		const CRtString &Host, 
		WORD aPort, 
		CRtHttpProxyInfo* &aPi) = 0;

protected:
	virtual ~IRtHttpProxyInfoGetter() { }
};

#ifdef RT_WIN32
class CPacResultAnaly;

class CRtHttpProxyInfoGetterFileBase
	: public CRtReferenceControlMutilThread
	, public IRtChannelSink
	, public CRtTimerWrapperSink
	, public IRtHttpProxyInfoGetter
{
protected:
	CRtHttpProxyInfoGetterFileBase(IRtObserver *aObserver);
	virtual ~CRtHttpProxyInfoGetterFileBase();

public:
	// interface IRtReferenceControl
	virtual DWORD AddReference();
	virtual DWORD ReleaseReference();
	
	// interface IRtChannelSink
	virtual void OnConnect(RtResult aReason, IRtChannel *aChannelId);
	
	// interface IRtTransportSink
	virtual void OnReceive(
		CRtMessageBlock &aData,
		IRtTransport *aTrptId,
		CRtTransportParameter *aPara = NULL);
	
	virtual void OnSend(
		IRtTransport *aTrptId,
		CRtTransportParameter *aPara = NULL);
	
	virtual void OnDisconnect(
		RtResult aReason,
		IRtTransport *aTrptId);

	// interface CRtTimerWrapperSink
	virtual void OnTimer(CRtTimerWrapper* aId);

	// interface IRtHttpProxyInfoGetter
	virtual RtResult StartUp(const CRtString &aData);

	virtual RtResult OnReceiveResonpse(CRtMessageBlock &aData) = 0;

protected:
	CRtAutoPtr<IRtChannelHttpClient>	m_pHttpChannel;
	enum {DOWNLOAD_SUCCESS, DOWNLOAD_FAILED, DOWNLOADING} m_dwState;
	CRtTimerWrapper m_TimerClose;
	IRtObserver *m_pObserver;
	DWORD m_dwRetryCount;
	CRtString m_strUrl;
	CRtChannelFile m_FileChannel;
};

class CRtHttpProxyInfoGetterPacFile 
	: public CRtHttpProxyInfoGetterFileBase
{
public:
	CRtHttpProxyInfoGetterPacFile(IRtObserver *aObserver);
	virtual ~CRtHttpProxyInfoGetterPacFile();

	// interface IRtHttpProxyInfoGetter
	virtual BOOL Reset(const CRtString &aHost, WORD aPort);
	virtual NextReturn GetNextProxyInfo(const CRtString &aHost, WORD aPort, CRtHttpProxyInfo* &aPi);
	
	// interface CRtHttpProxyInfoGetterFileBase
	virtual RtResult OnReceiveResonpse(CRtMessageBlock &aData);

private:
	CRtString m_strPacFile;
	CPacResultAnaly *m_pPacAnalyzer;
};

class CRtHttpProxyInfoGetterInsFile 
	: public CRtHttpProxyInfoGetterFileBase
	, public IRtObserver
{
public:
	CRtHttpProxyInfoGetterInsFile(IRtObserver *aObserver);
	virtual ~CRtHttpProxyInfoGetterInsFile();

	// interface IRtHttpProxyInfoGetter
	virtual BOOL Reset(const CRtString &aHost, WORD aPort);
	virtual NextReturn GetNextProxyInfo(const CRtString &aHost, WORD aPort, CRtHttpProxyInfo* &aPi);

	// interface CRtHttpProxyInfoGetterFileBase
	virtual RtResult OnReceiveResonpse(CRtMessageBlock &aData);

	// interface IRtObserver
	virtual void OnObserve(LPCSTR aTopic, LPVOID aData = NULL);

protected:
	CRtAutoPtr<CRtHttpProxyInfoGetterPacFile> m_pProxyInfoGetterPacFile;
};

class CRtHttpProxyInfoGetterManual
	: public CRtReferenceControlMutilThread
	, public IRtHttpProxyInfoGetter
{
public:
	CRtHttpProxyInfoGetterManual();
	virtual ~CRtHttpProxyInfoGetterManual();

	// interface IRtReferenceControl
	virtual DWORD AddReference();
	virtual DWORD ReleaseReference();

	virtual RtResult StartUp(const CRtString &aData);
	virtual BOOL Reset(const CRtString &aHost, WORD aPort);
	virtual NextReturn GetNextProxyInfo(const CRtString &aHost, WORD aPort, CRtHttpProxyInfo* &aPi);

	void SetBypass(const CRtString &aBypass, IRtHttpProxySetting::BrowseType aType);

public:
	struct CByPassEntry 
	{
		CByPassEntry() { }
		CByPassEntry(const CRtString &aHost, WORD aPort)
			: m_strHost(aHost)
			, m_wPort(aPort) 
		{ RT_ASSERTE(!m_strHost.empty()); }

		friend bool operator<(const CByPassEntry &aAtom1, const CByPassEntry &aAtom2) { return true; }
		friend bool operator==(const CByPassEntry &aAtom1, const CByPassEntry &aAtom2) { return true; }

		CRtString m_strHost;
		WORD m_wPort;
	};

	typedef std::vector<CByPassEntry> CByPassEntrysType;
private:
	CByPassEntrysType m_ByPassArray;

	BOOL IsByPass(const CRtString &aIpaddress, WORD aPort);
	void MoveNext(CRtString& aBuf, CRtHttpProxyInfo::PROXY_TYPE& aType);

	enum { FIND_HTTPS, FIND_HTTP, FIND_SOCKS, FIND_NONE } m_FindPos;

	CRtString m_strManual;
	CRtString m_strBypass;
	IRtHttpProxySetting::BrowseType m_BrowserType;
};
#endif // RT_WIN32

class /*RT_API_EXPORT*/ CRtHttpProxyInfoGetterByUpperLayer
	: public IRtHttpProxyInfoGetter
{
public:
	static CRtHttpProxyInfoGetterByUpperLayer* Instance();

	// interface IRtReferenceControl
	virtual DWORD AddReference();
	virtual DWORD ReleaseReference();

	virtual RtResult StartUp(const CRtString &aData);
	virtual BOOL Reset(const CRtString &aHost, WORD aPort);
	virtual NextReturn GetNextProxyInfo(const CRtString &aHost, WORD aPort, CRtHttpProxyInfo* &aPi);

	void RegisterNotifaction(IRtObserver *aObserver);
	void SetServerHttp(const CRtString &aIpAndPort);
	void SetServerHttps(const CRtString &aIpAndPort);

private:
	CRtHttpProxyInfoGetterByUpperLayer();
	virtual ~CRtHttpProxyInfoGetterByUpperLayer();

	enum { MAX_INDEX = 2};
	CRtString m_pServerIp[MAX_INDEX];
	CRtHttpProxyInfo::PROXY_TYPE m_pType[MAX_INDEX];
	int m_nIndex;
	IRtObserver *m_pObserver;

	friend class CRtSingletonT<CRtHttpProxyInfoGetterByUpperLayer>;
};

//typedef CRtSingletonT<CRtHttpProxyInfoGetterByUpperLayer> CRtHttpProxyInfoGetterByUpperLayerSingleton;

#endif // !RTHTTPPROXYINFOGETTER_H
